/*
 * PongLogic.hpp
 *
 *  Created on: Jun 4, 2009
 *      Author: asantos
 */

#ifndef PONGLOGIC_HPP_
#define PONGLOGIC_HPP_

class PongLogic{
public:
	typedef void(BallInPlayHandler)();
	typedef void(PlayerStartTurnHandler)();
private:
	SignalBroker& signalbroker;
	boost::signals::connection getselectedscenegraphconnection;
	Signal<PongPhysics::CollisionHandler>& ballandleftwallcollision;
	Signal<PongPhysics::CollisionHandler>& ballandrightwallcollision;

	enum Players{Player1 = 0, Player2};
	Players currentplayer;

	enum GameStates{WaitingForLaunch, BallInPlay};
	GameStates currentgamestate;

	int player1_score;
	int player2_score;

	bool initialized;
	SceneNode* ballnode;
	const SceneNode* player1node;
	const SceneNode* player2node;

	SceneNode* player1_0;
	SceneNode* player1_1;
	SceneNode* player1_2;
	SceneNode* player1_3;
	SceneNode* player1_4;
	SceneNode* player1_5;
	SceneNode* player1_6;
	SceneNode* player1_7;
	SceneNode* player1_8;
	SceneNode* player1_9;

	SceneNode* player2_0;
	SceneNode* player2_1;
	SceneNode* player2_2;
	SceneNode* player2_3;
	SceneNode* player2_4;
	SceneNode* player2_5;
	SceneNode* player2_6;
	SceneNode* player2_7;
	SceneNode* player2_8;
	SceneNode* player2_9;
public:
	PongLogic(SignalBroker& signalbroker):
		signalbroker(signalbroker),
		ballandleftwallcollision(signalbroker.CreateOrGetExistingSignal<PongPhysics::CollisionHandler>("/physics/ballandleftwallcollision")),
		ballandrightwallcollision(signalbroker.CreateOrGetExistingSignal<PongPhysics::CollisionHandler>("/physics/ballandrightwallcollision")),
		currentplayer(Player1),
		currentgamestate(WaitingForLaunch),
		player1_score(0),
		player2_score(0)
{

		Signal<SceneGraphController::GetSelectedSceneGraphHandler>& getselectedscenegraph = signalbroker.CreateOrGetExistingSignal<SceneGraphController::GetSelectedSceneGraphHandler>("/scenegraphcontroller/getselectedscenegraph");
		getselectedscenegraphconnection = getselectedscenegraph.connect(boost::bind(&PongLogic::GetSelectedSceneGraph, this, _1));

		Signal<Simulation1InputView::PlayerMovementHandler>& player1moveup = signalbroker.CreateOrGetExistingSignal<Simulation1InputView::PlayerMovementHandler>("/input/player1/moveup");
		player1moveup.connect(boost::bind(&PongLogic::MovePlayer1NodeUp, this, _1, _2));

		Signal<Simulation1InputView::PlayerMovementHandler>& player1movedown = signalbroker.CreateOrGetExistingSignal<Simulation1InputView::PlayerMovementHandler>("/input/player1/movedown");
		player1movedown.connect(boost::bind(&PongLogic::MovePlayer1NodeDown, this, _1, _2));

		Signal<Simulation1InputView::PlayerSelectHandler>& player1select = signalbroker.CreateOrGetExistingSignal<Simulation1InputView::PlayerSelectHandler>("/input/player1/select");
		player1select.connect(boost::bind(&PongLogic::Player1Select, this, _1, _2));

		Signal<Simulation1InputView::PlayerMovementHandler>& player2moveup = signalbroker.CreateOrGetExistingSignal<Simulation1InputView::PlayerMovementHandler>("/input/player2/moveup");
		player2moveup.connect(boost::bind(&PongLogic::MovePlayer2NodeUp, this, _1, _2));

		Signal<Simulation1InputView::PlayerMovementHandler>& player2movedown = signalbroker.CreateOrGetExistingSignal<Simulation1InputView::PlayerMovementHandler>("/input/player2/movedown");
		player2movedown.connect(boost::bind(&PongLogic::MovePlayer2NodeDown, this, _1, _2));

		Signal<Simulation1InputView::PlayerSelectHandler>& player2select = signalbroker.CreateOrGetExistingSignal<Simulation1InputView::PlayerSelectHandler>("/input/player2/select");
		player2select.connect(boost::bind(&PongLogic::Player2Select, this, _1, _2));

		ballandleftwallcollision.connect(boost::bind(&PongLogic::HandleBallAndLeftWallCollision, this));
		ballandrightwallcollision.connect(boost::bind(&PongLogic::HandleBallAndRightWallCollision, this));

	}
	void GetSelectedSceneGraph(SceneGraph& scenegraph){
		try{
			ballnode = scenegraph.GetRoot().GetChildNodePtrByName("ball");
			player1node = scenegraph.GetRoot().GetChildNodePtrByName("paddle0");
			player2node = scenegraph.GetRoot().GetChildNodePtrByName("paddle1");

			player1_0 = scenegraph.GetRoot().GetChildNodePtrByName("player0-0");
			player1_1 = scenegraph.GetRoot().GetChildNodePtrByName("player0-1");
			player1_2 = scenegraph.GetRoot().GetChildNodePtrByName("player0-2");
			player1_3 = scenegraph.GetRoot().GetChildNodePtrByName("player0-3");
			player1_4 = scenegraph.GetRoot().GetChildNodePtrByName("player0-4");
			player1_5 = scenegraph.GetRoot().GetChildNodePtrByName("player0-5");
			player1_6 = scenegraph.GetRoot().GetChildNodePtrByName("player0-6");
			player1_7 = scenegraph.GetRoot().GetChildNodePtrByName("player0-7");
			player1_8 = scenegraph.GetRoot().GetChildNodePtrByName("player0-8");
			player1_9 = scenegraph.GetRoot().GetChildNodePtrByName("player0-9");


			player2_0 = scenegraph.GetRoot().GetChildNodePtrByName("player1-0");
			player2_1 = scenegraph.GetRoot().GetChildNodePtrByName("player1-1");
			player2_2 = scenegraph.GetRoot().GetChildNodePtrByName("player1-2");
			player2_3 = scenegraph.GetRoot().GetChildNodePtrByName("player1-3");
			player2_4 = scenegraph.GetRoot().GetChildNodePtrByName("player1-4");
			player2_5 = scenegraph.GetRoot().GetChildNodePtrByName("player1-5");
			player2_6 = scenegraph.GetRoot().GetChildNodePtrByName("player1-6");
			player2_7 = scenegraph.GetRoot().GetChildNodePtrByName("player1-7");
			player2_8 = scenegraph.GetRoot().GetChildNodePtrByName("player1-8");
			player2_9 = scenegraph.GetRoot().GetChildNodePtrByName("player1-9");

			getselectedscenegraphconnection.disconnect();
			initialized = true;


			MoveBallWithPlayer1();
			signalbroker.InvokeSignal<PongLogic::PlayerStartTurnHandler>("/logic/player1/startturn");

		}catch(...){

		}
	}

	void MovePlayer1NodeUp(long t, long dt){
		if(initialized && currentgamestate == WaitingForLaunch && currentplayer == Player1){
			MoveBallWithPlayer1();
		}
	}
	void MovePlayer1NodeDown(long t, long dt){
		if(initialized && currentgamestate == WaitingForLaunch && currentplayer == Player1){
			MoveBallWithPlayer1();
		}
	}
	void Player1Select(long t, long dt){
		if(initialized && currentgamestate == WaitingForLaunch && currentplayer == Player1){
			currentgamestate = BallInPlay;
			PhysicsProperty& ballphysical = ballnode->GetSceneNodeProperty<PhysicsProperty>("physical");

			Vector3& vball = dynamic_cast<PongPhysical*>(ballphysical.GetPhysicalPtr())->GetVelocity();
			vball[0]=-200;
			signalbroker.InvokeSignal<PongLogic::BallInPlayHandler>("/logic/ball/inplay");
		}
	}
	void MovePlayer2NodeUp(long t, long dt){
		if(initialized && currentgamestate == WaitingForLaunch && currentplayer == Player2){
			MoveBallWithPlayer2();
		}
	}
	void MovePlayer2NodeDown(long t, long dt){
		if(initialized && currentgamestate == WaitingForLaunch && currentplayer == Player2){
			MoveBallWithPlayer2();
		}
	}
	void Player2Select(long t, long dt){
		if(initialized && currentgamestate == WaitingForLaunch && currentplayer == Player2){
			currentgamestate = BallInPlay;
			PhysicsProperty& ballphysical = ballnode->GetSceneNodeProperty<PhysicsProperty>("physical");

			Vector3& vball = dynamic_cast<PongPhysical*>(ballphysical.GetPhysicalPtr())->GetVelocity();
			vball[0]=200;

			signalbroker.InvokeSignal<BallInPlayHandler>("/logic/ball/inplay");
		}
	}
protected:
	void MoveBallWithPlayer1(){
		if(initialized && currentgamestate == WaitingForLaunch && currentplayer == Player1){
			PositionProperty& player1position = player1node->GetSceneNodeProperty<PositionProperty>("position");
			PositionProperty& ballposition = ballnode->GetSceneNodeProperty<PositionProperty>("position");

			Matrix4& mplayer = player1position.GetPosition();
			Matrix4& mball = ballposition.GetPosition();
			mball=mplayer;
			mball(0,3)-=17;
		}
	}
	void MoveBallWithPlayer2(){
		if(initialized && currentgamestate == WaitingForLaunch && currentplayer == Player2){
			PositionProperty& player2position = player2node->GetSceneNodeProperty<PositionProperty>("position");
			PositionProperty& ballposition = ballnode->GetSceneNodeProperty<PositionProperty>("position");

			Matrix4& mplayer = player2position.GetPosition();
			Matrix4& mball = ballposition.GetPosition();
			mball=mplayer;
			mball(0,3)+=17;
		}
	}
	void HandleBallAndLeftWallCollision(){
		if(initialized){
			IncrementPlayer1Score();
			currentgamestate = WaitingForLaunch;
			currentplayer = Player1;
			PhysicsProperty& ballphysical = ballnode->GetSceneNodeProperty<PhysicsProperty>("physical");
			Vector3& vball = dynamic_cast<PongPhysical*>(ballphysical.GetPhysicalPtr())->GetVelocity();
			vball[0]=0;
			vball[1]=0;
			MoveBallWithPlayer1();
			signalbroker.InvokeSignal<PongLogic::PlayerStartTurnHandler>("/logic/player1/startturn");
		}
	}

	void HandleBallAndRightWallCollision(){
		if(initialized){
			IncrementPlayer2Score();
			currentgamestate = WaitingForLaunch;
			currentplayer = Player2;
			PhysicsProperty& ballphysical = ballnode->GetSceneNodeProperty<PhysicsProperty>("physical");
			Vector3& vball = dynamic_cast<PongPhysical*>(ballphysical.GetPhysicalPtr())->GetVelocity();
			vball[0]=0;
			vball[1]=0;
			MoveBallWithPlayer2();
			signalbroker.InvokeSignal<PongLogic::PlayerStartTurnHandler>("/logic/player2/startturn");
		}
	}
	void IncrementPlayer1Score(){

		/*IRenderable& renderable_0 = player1_0->GetSceneNodeProperty<IRenderable>("renderable");
		IRenderable& renderable_1 = player1_1->GetSceneNodeProperty<IRenderable>("renderable");
		std::stringstream ss;
		ss << "IncrementPlayer1Score" << std::endl;
		ss << "player1_0.IsVisible():" << renderable_0.IsVisible() << std::endl;
		ss << "player1_1.IsVisible():" << renderable_1.IsVisible() << std::endl;

		signalbroker.InvokeSignal("/log/output", (ArgsList(), ss.str()));*/

		switch(player1_score){
		case 0:
			player1_0->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
			player1_1->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);
			break;
		case 1:
			player1_1->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
			player1_2->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);
			break;
		case 2:
			player1_2->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
			player1_3->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);
			break;
		case 3:
			player1_3->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
			player1_4->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);
			break;
		case 4:
			player1_4->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
			player1_5->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);
			break;
		case 5:
			player1_5->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
			player1_6->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);
			break;
		case 6:
			player1_6->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
			player1_7->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);
			break;
		case 7:
			player1_7->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
			player1_8->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);
			break;
		case 8:
			player1_8->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
			player1_9->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);
			break;
		case 9:

			player1_9->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
			player1_0->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);

			player2_1->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
			player2_2->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
			player2_3->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
			player2_4->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
			player2_5->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
			player2_6->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
			player2_7->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
			player2_8->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
			player2_9->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);

			player2_0->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);

			player1_score = -1;
			player2_score = 0;
			break;
		}
		player1_score+=1;

	}

	void IncrementPlayer2Score(){
		switch(player2_score){
			case 0:
				player2_0->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
				player2_1->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);
				break;
			case 1:
				player2_1->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
				player2_2->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);
				break;
			case 2:
				player2_2->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
				player2_3->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);
				break;
			case 3:
				player2_3->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
				player2_4->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);
				break;
			case 4:
				player2_4->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
				player2_5->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);
				break;
			case 5:
				player2_5->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
				player2_6->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);
				break;
			case 6:
				player2_6->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
				player2_7->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);
				break;
			case 7:
				player2_7->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
				player2_8->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);
				break;
			case 8:
				player2_8->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
				player2_9->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);
				break;
			case 9:
				player1_1->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
				player1_2->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
				player1_3->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
				player1_4->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
				player1_5->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
				player1_6->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
				player1_7->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
				player1_8->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
				player1_9->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);

				player1_0->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);

				player2_9->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(false);
				player2_0->GetSceneNodeProperty<RenderableProperty>("renderable").GetRenderable().SetVisibility(true);

				player1_score = 0;
				player2_score = -1;
				break;
		}
		player2_score+=1;

	}

};

#endif /* PONGLOGIC_HPP_ */
